package org.terracotta.workmanager.queue;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class ListBasedQueue<T> implements Queue<T> {
  private final List<T> list;

  //private final int maxSize;

  public static class Factory<T> implements Queue.Factory<T> {
    private final int m_size;

    public Factory() {
      this(1000);
    }

    public Factory(final int size) {
      super();
      m_size = size;
    }

    public Queue<T> create() {
      return new ListBasedQueue<T>(new ArrayList<T>(), m_size);
    }
  }

  public ListBasedQueue() {
    this(new ArrayList<T>(), 1000);
  }

  public ListBasedQueue(final List<T> list, int maxSize) {
    this.list = list;
    //this.maxSize = maxSize;
  }

  public T put(T item) {
    synchronized (list) {
      /*while (list.size() >= maxSize) {
        list.wait();
      }*/

      list.add(item);
      list.notify();
    }

    return item;
  }

  public T take() throws InterruptedException {
    synchronized (list) {
      while (list.isEmpty()) {
        list.wait();
      }

      return list.remove(0);
    }
  }

  public T poll(long timeout, TimeUnit unit) throws InterruptedException {
    long started = System.currentTimeMillis();
    synchronized (list) {
      while (list.isEmpty()) {        
        if (System.currentTimeMillis() - started >= unit.toMillis(timeout)) {
          return null;
        }
        list.wait( unit.toMillis(timeout) - System.currentTimeMillis() + started);
      }

      return list.remove(0);
    }
  }
  
  public T polledPeek(long timeout, TimeUnit unit) throws InterruptedException {
    long started = System.currentTimeMillis();
    synchronized (list) {
      
      while (list.isEmpty()) {        
        if (System.currentTimeMillis() - started >= unit.toMillis(timeout)) {
          return null;
        }
        list.wait( unit.toMillis(timeout) - System.currentTimeMillis() + started);
      }

      return list.get(0);
    }
  }

  public T peek() throws InterruptedException {
    synchronized (list) {
      while (list.isEmpty()) {
        list.wait();
      }

      return list.get(0);
    }
  }

  public int size() {
    synchronized (list) {
      return list.size();
    }
  }

  public void clear() {
    synchronized (list) {
      list.clear();
    }
  }


  public Iterator<T> iterator() {
    return list.iterator();
  }
}
